package com.bowlong.lang;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.bowlong.concurrent.async.Async;

@SuppressWarnings({})
public class Memory {
	static final Map<Object, MemoryNSpace> MAP = new ConcurrentHashMap<>();

	static final MemoryNSpace sp(String name) {
		MemoryNSpace ms = MAP.get(name);
		if (ms == null) {
			ms = MemoryNSpace.getInstance(name);
			MAP.put(name, ms);
		}
		return ms;
	}

	static final String NAME = "static";

	// ////////////////////////
	public static final <T> T get(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return get(sp, key);
	}

	public static final <T> T set(String namespace, Object key, T value) {
		MemoryNSpace sp = sp(namespace);
		return set(sp, key, value);
	}

	// 取出旧值,存入新值
	public static final <T> T getSet(String namespace, Object key, T value) {
		MemoryNSpace sp = sp(namespace);
		return getSet(sp, key, value);
	}

	// 不存在则覆盖
	public static final <T> T setNoOverlap(String namespace, Object key, T value) {
		MemoryNSpace sp = sp(namespace);
		return setNoOverlap(sp, key, value);
	}

	// 存在才覆盖
	public static final <T> T setOnOverlap(String namespace, Object key, T value) {
		MemoryNSpace sp = sp(namespace);
		return setOnOverlap(sp, key, value);
	}

	// 获得值并且自增
	public static final int incrementAndGet(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return incrementAndGet(sp, key);
	}

	// 获得值并且自增
	public static final int getAdd(String namespace, Object key, int add) {
		MemoryNSpace sp = sp(namespace);
		return getAdd(sp, key, add);
	}

	// 获得值并且自增
	public static final int addGet(String namespace, Object key, int add) {
		MemoryNSpace sp = sp(namespace);
		return addGet(sp, key, add);
	}

	// 获得值并且自减
	public static final int decrementAndGet(String namespace, Object key,
			int initval) {
		MemoryNSpace sp = sp(namespace);
		return decrementAndGet(sp, key, initval);
	}

	public static final boolean getBool(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return getBool(sp, key);
	}

	public static final boolean getSet(String namespace, Object key,
			boolean value) {
		MemoryNSpace sp = sp(namespace);
		return getSet(sp, key, value);
	}

	public static final byte getByte(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return getByte(sp, key);
	}

	public static final byte getSet(String namespace, Object key, byte value) {
		MemoryNSpace sp = sp(namespace);
		return getSet(sp, key, value);
	}

	public static final short getShort(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return getShort(sp, key);
	}

	public static final short getSet(String namespace, Object key, short value) {
		MemoryNSpace sp = sp(namespace);
		return getSet(sp, key, value);
	}

	public static final int getInt(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return getInt(sp, key);
	}

	public static final int getSet(String namespace, Object key, int value) {
		MemoryNSpace sp = sp(namespace);
		return getSet(sp, key, value);
	}

	public static final long getLong(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return getLong(sp, key);
	}

	public static final long getSet(String namespace, Object key, long value) {
		MemoryNSpace sp = sp(namespace);
		return getSet(sp, key, value);
	}

	public static final float getFloat(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return getFloat(sp, key);
	}

	public static final float getSet(String namespace, Object key, float value) {
		MemoryNSpace sp = sp(namespace);
		return getSet(sp, key, value);
	}

	public static final double getDouble(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return getDouble(sp, key);
	}

	public static final double getSet(String namespace, Object key, double value) {
		MemoryNSpace sp = sp(namespace);
		return getSet(sp, key, value);
	}

	public static final String getString(String namespace, Object key) {
		MemoryNSpace sp = sp(namespace);
		return getString(sp, key);
	}

	public static final String getSet(String namespace, Object key, String value) {
		MemoryNSpace sp = sp(namespace);
		return getSet(sp, key, value);
	}

	public static final void save(String namespace) throws IOException {
		MemoryNSpace sp = sp(namespace);
		save(sp);
	}

	public static final void load(String namespace) throws IOException,
			ClassNotFoundException {
		MemoryNSpace sp = sp(namespace);
		load(sp);
	}

	public static final void asyncSave(String namespace) {
		MemoryNSpace sp = sp(namespace);
		asyncSave(sp);
	}

	public static final void clear(String namespace) {
		MemoryNSpace sp = sp(namespace);
		clear(sp);
	}

	// ////////////////////////
	public static final <T> T get(Object key) {
		MemoryNSpace sp = sp(NAME);
		return get(sp, key);
	}

	public static final <T> T set(Object key, T value) {
		MemoryNSpace sp = sp(NAME);
		return set(sp, key, value);
	}

	// 取出旧值,存入新值
	public static final <T> T getSet(Object key, T value) {
		MemoryNSpace sp = sp(NAME);
		return getSet(sp, key, value);
	}

	// 不存在则覆盖
	public static final <T> T setNoOverlap(Object key, T value) {
		MemoryNSpace sp = sp(NAME);
		return setNoOverlap(sp, key, value);
	}

	// 存在才覆盖
	public static final <T> T setOnOverlap(Object key, T value) {
		MemoryNSpace sp = sp(NAME);
		return setOnOverlap(sp, key, value);
	}

	// 获得值并且自增
	public static final int incrementAndGet(Object key) {
		MemoryNSpace sp = sp(NAME);
		return incrementAndGet(sp, key);
	}

	// 获得值并且自增
	public static final int getAdd(Object key, int add) {
		MemoryNSpace sp = sp(NAME);
		return getAdd(sp, key, add);
	}

	// 获得值并且自增
	public static final int addGet(Object key, int add) {
		MemoryNSpace sp = sp(NAME);
		return addGet(sp, key, add);
	}

	// 获得值并且自减
	public static final int decrementAndGet(Object key, int initval) {
		MemoryNSpace sp = sp(NAME);
		return decrementAndGet(sp, key, initval);
	}

	public static final boolean getBool(Object key) {
		MemoryNSpace sp = sp(NAME);
		return getBool(sp, key);
	}

	public static final boolean getSet(Object key, boolean value) {
		MemoryNSpace sp = sp(NAME);
		return getSet(sp, key, value);
	}

	public static final byte getByte(Object key) {
		MemoryNSpace sp = sp(NAME);
		return getByte(sp, key);
	}

	public static final byte getSet(Object key, byte value) {
		MemoryNSpace sp = sp(NAME);
		return getSet(sp, key, value);
	}

	public static final short getShort(Object key) {
		MemoryNSpace sp = sp(NAME);
		return getShort(sp, key);
	}

	public static final short getSet(Object key, short value) {
		MemoryNSpace sp = sp(NAME);
		return getSet(sp, key, value);
	}

	public static final int getInt(Object key) {
		MemoryNSpace sp = sp(NAME);
		return getInt(sp, key);
	}

	public static final int getSet(Object key, int value) {
		MemoryNSpace sp = sp(NAME);
		return getSet(sp, key, value);
	}

	public static final long getLong(Object key) {
		MemoryNSpace sp = sp(NAME);
		return getLong(sp, key);
	}

	public static final long getSet(Object key, long value) {
		MemoryNSpace sp = sp(NAME);
		return getSet(sp, key, value);
	}

	public static final float getFloat(Object key) {
		MemoryNSpace sp = sp(NAME);
		return getFloat(sp, key);
	}

	public static final float getSet(Object key, float value) {
		MemoryNSpace sp = sp(NAME);
		return getSet(sp, key, value);
	}

	public static final double getDouble(Object key) {
		MemoryNSpace sp = sp(NAME);
		return getDouble(sp, key);
	}

	public static final double getSet(Object key, double value) {
		MemoryNSpace sp = sp(NAME);
		return getSet(sp, key, value);
	}

	public static final String getString(Object key) {
		MemoryNSpace sp = sp(NAME);
		return getString(sp, key);
	}

	public static final String getSet(Object key, String value) {
		MemoryNSpace sp = sp(NAME);
		return getSet(sp, key, value);
	}

	public static final void save() throws IOException {
		MemoryNSpace sp = sp(NAME);
		save(sp);
	}

	public static final void load() throws IOException, ClassNotFoundException {
		MemoryNSpace sp = sp(NAME);
		load(sp);
	}

	public static final void asyncSave() {
		MemoryNSpace sp = sp(NAME);
		asyncSave(sp);
	}

	public static final void clear() {
		MemoryNSpace sp = sp(NAME);
		clear(sp);
	}

	// ///////////////////
	static final <T> T get(MemoryNSpace sp, Object key) {
		return sp.get(key);
	}

	static final <T> T set(MemoryNSpace sp, Object key, T value) {
		return sp.set(key, value);
	}

	// 取出旧值,存入新值
	static final <T> T getSet(MemoryNSpace sp, Object key, T value) {
		return sp.getSet(key, value);
	}

	// 不存在则覆盖
	static final <T> T setNoOverlap(MemoryNSpace sp, Object key, T value) {
		return sp.setNoOverlap(key, value);
	}

	// 存在才覆盖
	static final <T> T setOnOverlap(MemoryNSpace sp, Object key, T value) {
		return sp.setOnOverlap(key, value);
	}

	// 获得值并且自增
	static final int incrementAndGet(MemoryNSpace sp, Object key) {
		return sp.incrementAndGet(key);
	}

	// 获得值并且自增
	static final int getAdd(MemoryNSpace sp, Object key, int add) {
		return sp.getAdd(key, add);
	}

	// 获得值并且自增
	static final int addGet(MemoryNSpace sp, Object key, int add) {
		return sp.addGet(key, add);
	}

	// 获得值并且自减
	static final int decrementAndGet(MemoryNSpace sp, Object key, int initval) {
		return sp.decrementAndGet(key, initval);
	}

	static final boolean getBool(MemoryNSpace sp, Object key) {
		return sp.getBool(key);
	}

	static final boolean getSet(MemoryNSpace sp, Object key, boolean value) {
		return sp.getSet(key, value);
	}

	static final byte getByte(MemoryNSpace sp, Object key) {
		return sp.getByte(key);
	}

	static final byte getSet(MemoryNSpace sp, Object key, byte value) {
		return sp.getSet(key, value);
	}

	static final short getShort(MemoryNSpace sp, Object key) {
		return sp.getShort(key);
	}

	static final short getSet(MemoryNSpace sp, Object key, short value) {
		return sp.getSet(key, value);
	}

	static final int getInt(MemoryNSpace sp, Object key) {
		return sp.getInt(key);
	}

	static final int getSet(MemoryNSpace sp, Object key, int value) {
		return sp.getSet(key, value);
	}

	static final long getLong(MemoryNSpace sp, Object key) {
		return sp.getLong(key);
	}

	static final long getSet(MemoryNSpace sp, Object key, long value) {
		return sp.getSet(key, value);
	}

	static final float getFloat(MemoryNSpace sp, Object key) {
		return sp.getFloat(key);
	}

	static final float getSet(MemoryNSpace sp, Object key, float value) {
		return sp.getSet(key, value);
	}

	static final double getDouble(MemoryNSpace sp, Object key) {
		return sp.getDouble(key);
	}

	static final double getSet(MemoryNSpace sp, Object key, double value) {
		return sp.getSet(key, value);
	}

	static final String getString(MemoryNSpace sp, Object key) {
		return sp.getString(key);
	}

	static final String getSet(MemoryNSpace sp, Object key, String value) {
		return sp.getSet(key, value);
	}

	public static final void save(MemoryNSpace sp) throws IOException {
		sp.save();
	}

	static final void load(MemoryNSpace sp) throws IOException,
			ClassNotFoundException {
		sp.load();
	}

	static final void asyncSave(MemoryNSpace sp) {
		sp.asyncSave();
	}

	static final void clear(MemoryNSpace sp) {
		sp.clear();
	}

	// /////////
	@SuppressWarnings("unchecked")
	static class MemoryNSpace {
		public static MemoryNSpace getInstance(String namespace) {
			return new MemoryNSpace(namespace);
		}

		public final String space;
		final Map<Object, Object> MAP = new ConcurrentHashMap<>();
		final File FILE;

		private MemoryNSpace(String namespace) {
			this.space = namespace;
			FILE = new File("memory_" + namespace + ".bytearray");
			try {
				load();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		public final <T> T get(Object key) {
			Object obj = MAP.get(key);
			return (T) obj;
		}

		public final <T> T set(Object key, T value) {
			MAP.put(key, value);
			return value;
		}

		// 取出旧值,存入新值
		public final <T> T getSet(Object key, T value) {
			T r2 = get(key);
			set(key, value);
			return r2;
		}

		// 不存在则覆盖
		public final <T> T setNoOverlap(Object key, T value) {
			T r2 = get(key);
			if (r2 == null)
				set(key, value);
			return r2;
		}

		// 存在才覆盖
		public final <T> T setOnOverlap(Object key, T value) {
			T r2 = get(key);
			if (r2 != null)
				set(key, value);
			return r2;
		}

		// 获得值并且自增
		public final synchronized int incrementAndGet(Object key) {
			Integer value = get(key);
			if (value == null) {
				value = 0;
				set(key, value);
			} else {
				value = value + 1;
				set(key, value);
			}

			return value;
		}

		// 获得值并且自增
		public final synchronized int getAdd(Object key, int add) {
			Integer value = get(key);
			if (value == null) {
				value = 0;
				set(key, add);
			} else {
				set(key, value + add);
			}
			return value;
		}

		// 获得值并且自增
		public final synchronized int addGet(Object key, int add) {
			Integer value = get(key);
			if (value == null) {
				value = add;
				set(key, value);
			} else {
				value = value + add;
				set(key, value);
			}
			return value;
		}

		// 获得值并且自减
		public final synchronized int decrementAndGet(Object key, int initval) {
			Integer value = get(key);
			if (value == null) {
				value = initval;
				set(key, value);
			} else {
				value = value - 1;
				set(key, value);
			}
			return value;
		}

		public final boolean getBool(Object key) {
			Boolean v = get(key);
			if (v == null)
				return false;
			return v.booleanValue();
		}

		public final boolean getSet(Object key, boolean value) {
			Boolean v = get(key);
			set(key, value);
			if (v == null)
				return false;
			return v.booleanValue();
		}

		public final byte getByte(Object key) {
			Byte v = get(key);
			if (v == null)
				return 0;
			return v.byteValue();
		}

		public final byte getSet(Object key, byte value) {
			Byte v = get(key);
			set(key, value);
			if (v == null)
				return 0;
			return v.byteValue();
		}

		public final short getShort(Object key) {
			Short v = get(key);
			if (v == null)
				return 0;
			return v.shortValue();
		}

		public final short getSet(Object key, short value) {
			Short v = get(key);
			set(key, value);
			if (v == null)
				return 0;
			return v.shortValue();
		}

		public final int getInt(Object key) {
			Integer v = get(key);
			if (v == null)
				return 0;
			return v.intValue();
		}

		public final int getSet(Object key, int value) {
			Integer v = get(key);
			set(key, value);
			if (v == null)
				return 0;
			return v.intValue();
		}

		public final long getLong(Object key) {
			Long v = get(key);
			if (v == null)
				return 0;
			return v.longValue();
		}

		public final long getSet(Object key, long value) {
			Long v = get(key);
			set(key, value);
			if (v == null)
				return 0;
			return v.longValue();
		}

		public final float getFloat(Object key) {
			Float v = get(key);
			if (v == null)
				return 0;
			return v.floatValue();
		}

		public final float getSet(Object key, float value) {
			Float v = get(key);
			set(key, value);
			if (v == null)
				return 0;
			return v.floatValue();
		}

		public final double getDouble(Object key) {
			Double v = get(key);
			if (v == null)
				return 0;
			return v.doubleValue();
		}

		public final double getSet(Object key, double value) {
			Float v = get(key);
			set(key, value);
			if (v == null)
				return 0;
			return v.doubleValue();
		}

		public final String getString(Object key) {
			String v = get(key);
			if (v == null)
				return "";
			return v;
		}

		public final String getSet(Object key, String value) {
			String v = get(key);
			set(key, value);
			if (v == null)
				return "";
			return v;
		}

		public final synchronized void save() throws IOException {
			synchronized (FILE) {
				try (FileOutputStream fos = new FileOutputStream(FILE);
						BufferedOutputStream bos = new BufferedOutputStream(fos);
						ObjectOutputStream oos = new ObjectOutputStream(bos);) {
					oos.writeObject(MAP);
					oos.flush();
					fos.flush();
				}
			}
		}

		public final void load() throws IOException, ClassNotFoundException {
			synchronized (FILE) {
				if (!FILE.exists()) {
					System.out.println(FILE + " no exists.");
					return;
				}
				try (FileInputStream fis = new FileInputStream(FILE);
						BufferedInputStream bis = new BufferedInputStream(fis);
						ObjectInputStream ois = new ObjectInputStream(bis);) {
					Map<Object, Object> map = (Map<Object, Object>) ois
							.readObject();
					MAP.clear();
					MAP.putAll(map);

					System.out.println("load: " + FILE + " num:" + MAP.size());
				}
			}
		}

		public final void asyncSave() {
			Async.exec(new Runnable() {
				@Override
				public void run() {
					try {
						save();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			});
		}

		public final void clear() {
			MAP.clear();
		}

	}

	public static void main(String[] args) throws IOException {
		int obj = Memory.getInt("a", "123");
		System.out.println(obj);
		Memory.incrementAndGet("a", "123");
		Memory.save("a");
	}
}
